<?php

/**
 * AjaxController
 *
 * @author Hua yang <htmlcook@gmail.com>
 */
class AjaxController extends BController
{
	protected function beforeAction($action)
	{
		if (parent::beforeAction($action)) {
			header('Content-Type: application/json; charset=' . Yii::app()->charset);
			return true;
		} else {
			return false;
		}
	}

	protected  function afterAction($action)
	{
		parent::afterAction($action);
		Yii::app()->end();
	}

	public function actionIndex()
	{
		if (isset($_REQUEST['action'])) {
			$_REQUEST['_action'] = $_REQUEST['action'];
			unset($_REQUEST['action']);
		}

		if (isset($_REQUEST['_action'])) {
			$method = 'action' . str_replace('-', '', $_REQUEST['_action']);
			if (method_exists($this, $method)) {
				$reflectionMethod = new ReflectionMethod($this, $method);
				$params = array();
				foreach ($reflectionMethod->getParameters() as $parameter) {
					if (isset($_GET[$parameter->getName()])) {
						$params[] = $_GET[$parameter->getName()];
					} elseif ($parameter->isDefaultValueAvailable()) {
						$params[] = $parameter->getDefaultValue();
					} else {
						throw new CHttpException(400, Yii::t('yii','Your request is invalid.'));
					}
				}
				call_user_func_array(array($this, $method), $params);
			}
		}
	}

	public function actionQueryAttachments()
	{
		$criteria = new CDbCriteria(array(
			'order' => 'create_time desc'
		));

		$pagination = new CPagination(File::model()->count());

		if (!empty($_POST['query']['post_mime_type'])) {
			$criteria->compare('filemime', $_POST['query']['post_mime_type'], true);
		}

		if (!empty($_POST['query']['s'])) {
			$criteria->compare('filename', $_POST['query']['s'], true);
		}

		if (isset($_POST['query']['orderby'])) {
			if ($_POST['query']['orderby'] == 'date') {
				if (isset($_POST['query']['order']) && in_array(strtolower($_POST['query']['order']), array('asc', 'desc'))) {
					$order = strtolower($_POST['query']['order']);
				} else {
					$order = 'desc';
				}
				$criteria->order = "create_time $order";
			}
		}

		if (isset($_POST['query']['posts_per_page'])) {
			$pagination->setPageSize(intval($_POST['query']['posts_per_page']));
		}

		if (isset($_POST['query']['paged'])) {
			$pagination->setCurrentPage(max(intval($_POST['query']['paged']), 1) - 1);
		}

		$pagination->applyLimit($criteria);

		$files = File::model()->findAll($criteria);
		$data = array();
		/** @var File $file */
		foreach ($files as $file) {
			$data[] = $file->toAttachment();
		}

		echo CJSON::encode(array('success' => true, 'data'=>$data));
	}

	public function actionDeleteAttachment()
	{
		$isAjax = Yii::app()->getRequest()->getIsAjaxRequest() || isset($_GET['ajax']);

		if (Yii::app()->request->isPostRequest && !empty($_POST['id'])) {
			$model = File::model()->findByPk($_POST['id']);
			if ($model === null) {
				throw new CHttpException(404, '页面没有找到');
			}

			if ($model->bundle === 'File') {
				$result = $model->delete();
			}

			if ($isAjax) {
				if (!empty($result)) {
					echo CJSON::encode(array('success' => true, 'data'=>array('message' => '删除文件成功')));
				} else {
					echo CJSON::encode(array('success' => false, 'data'=>array('message' => '删除文件失败')));
				}
			}
		} else {
			throw new CHttpException(405, '无效的请求，请重试');
		}
	}

	public function actionSaveAttachment()
	{
		$isAjax = Yii::app()->getRequest()->getIsAjaxRequest() || isset($_GET['ajax']);
		if (Yii::app()->request->isPostRequest && !empty($_POST['id'])) {
			$model = File::model()->findByPk($_POST['id']);
			if ($model === null) {
				throw new CHttpException(404, '页面没有找到');
			}

			if (isset($_POST['changes']) && is_array($_POST['changes'])) {
				if (isset($_POST['changes']['title'])) {
					$_POST['changes']['name'] = $_POST['changes']['title'];
					unset($_POST['changes']['title']);
				}
				$model->setAttributes($_POST['changes']);
				$result = $model->save();
			}

			if ($isAjax) {
				if (!empty($result)) {
					echo CJSON::encode(array('success' => true, 'data'=>array('message' => '保存文件成功')));
				} else {
					echo CJSON::encode(array('success' => false, 'data'=>array('message' => '保存文件失败')));
				}
			}
		} else {
			throw new CHttpException(405, '无效的请求，请重试');
		}
	}

	public function actionGetAttachment()
	{
		$isAjax = Yii::app()->getRequest()->getIsAjaxRequest() || isset($_GET['ajax']);
		if (Yii::app()->request->isPostRequest && !empty($_POST['id'])) {
			$model = File::model()->findByPk($_POST['id']);
			if ($model === null) {
				throw new CHttpException(404, '页面没有找到');
			}
			echo CJSON::encode(array('success' => true, 'data'=>$model->toAttachment()));
		} else {
			throw new CHttpException(405, '无效的请求，请重试');
		}
	}

	public function actionImageEditor()
	{
		$isAjax = Yii::app()->getRequest()->getIsAjaxRequest() || isset($_GET['ajax']);
		if ($isAjax && !empty($_POST['postid'])) {
			/** @var File $model */
			$model = File::model()->findByPk($_POST['postid']);
			if ($model === null) {
				throw new CHttpException(404, '页面没有找到');
			} elseif ($model->getType() !== 'image') {
				throw new CException('文件不是图片');
			}

			switch($_POST['do']) {
				case 'save':
				case 'scale':
					/** @var YImage $YImage */
					$YImage = Yii::app()->getImage();
					$image = $YImage->load($model->getPath());

					if ($_POST['do'] === 'save') {
						$changes = !empty($_REQUEST['history']) ? json_decode($_REQUEST['history']) : null;
						$target = !empty($_REQUEST['target']) ? preg_replace('/[^a-z0-9_-]+/i', '', $_REQUEST['target']) : '';
						if ($changes) {
							$this->imageEditApplyChanges($image, $changes);
						}
					} else {
						$fWidth = !empty($_REQUEST['fwidth']) ? intval($_REQUEST['fwidth']) : 0;
						$fHeight = !empty($_REQUEST['fheight']) ? intval($_REQUEST['fheight']) : 0;

						list($sX, $sY) = $image->getSize();
						// check if it has roughly the same w / h ratio
						$diff = round($sX / $sY, 2) - round($fWidth / $fHeight, 2);
						if ( -0.1 < $diff && $diff < 0.1 ) {
							// scale the full size image
							$image->resize( $fWidth, $fHeight );
							$target = 'scale';
						} else {
							$result = array('error' => '图片拉伸失败');
							break;
						}
					}
					$result = $this->saveImage($model, $image, $target);
					if ($_POST['do'] == 'save') {
						header('Content-Type: text/html; charset=' . Yii::app()->charset);
						echo json_encode($result);
						return;
					}
					break;
				case 'restore':
					$result = $this->restoreImage($model);
					break;
			}

			header('Content-Type: text/html; charset=' . Yii::app()->charset);
			$this->renderPartial('imageEditor', array('model'=>$model, 'result' => isset($result) ? $result : array()));
		} else {
			throw new CHttpException(405, '无效的请求，请重试');
		}
	}

	public function actionImgEditPreview()
	{
		if (!empty($_GET['postid'])) {
			$model = File::model()->findByPk($_GET['postid']);
		}

		if (empty($model) || $model->getType() !== 'image') {
			throw new CHttpException(404, '图片没有找到');
		}

		/** @var YImage $YImage */
		$YImage = Yii::app()->getImage();
		$image = $YImage->load($model->getPath());
		$changes = !empty($_REQUEST['history']) ? json_decode($_REQUEST['history']) : null;
		if ($changes) {
			$this->imageEditApplyChanges($image, $changes);
		}
		list($w, $h) = $image->getSize();
		$ratio = $this->imageGetPreviewRatio($w, $h);
		$image->resize(max(1, $w*$ratio), max(1, $h*$ratio));
		$image->show($model->getExt());
	}

	/**
	 * @param File $imageModel
	 * @return array
	 */
	protected function restoreImage(File $imageModel)
	{
		if (isset($imageModel->meta['_backup_sizes'])) {
			$backupSizes = $imageModel->meta['_backup_sizes'];
		} else {
			return array(
				'error' => '没有找到图片备份信息'
			);
		}

		$dimensions = $imageModel->getDimensions();
		$meta = $imageModel->meta;
		$filePath = $imageModel->getPath();
		$parts = pathinfo($filePath);
		$suffix = time() . rand(100, 999);
		$defaultSizes = File::getIntermediateImageSizes();
		if ( isset($backupSizes[File::IMAGE_ORIGIN . '-orig']) && is_array($backupSizes[File::IMAGE_ORIGIN . '-orig']) ) {
			$data = $backupSizes[File::IMAGE_ORIGIN . '-orig'];

			if ( $imageModel->uri != $data['uri'] ) {
				if ( Yii::app()->getOption()->get('image_edit_overwrite', false)) {
					// delete only if it's edited image
					if ( preg_match('/-e[0-9]{13}\./', $parts['basename']) ) {
						@unlink($filePath);
					}
				} elseif ( isset( $dimensions['width'], $dimensions['height'] ) ) {
					$backupSizes[File::IMAGE_ORIGIN."-$suffix"] = array('width' => $dimensions['width'], 'height' => $dimensions['height'], 'uri' => $dimensions['uri']);
				}
			}

			$imageModel->uri = $data['uri'];
			$meta['sizes'][File::IMAGE_ORIGIN]['uri'] = $data['uri'];
			$meta['sizes'][File::IMAGE_ORIGIN]['width'] = $data['width'];
			$meta['sizes'][File::IMAGE_ORIGIN]['height'] = $data['height'];
		}

		foreach ( $defaultSizes as $defaultSize ) {
			if ( isset($backupSizes["$defaultSize-orig"]) ) {
				$data = $backupSizes["$defaultSize-orig"];
				if ( isset($meta['sizes'][$defaultSize]) && $meta['sizes'][$defaultSize]['uri'] != $data['uri'] ) {
					if ( Yii::app()->getOption()->get('image_edit_overwrite', false)) {
						// delete only if it's edited image
						if ( preg_match('/-e[0-9]{13}-/', $meta['sizes'][$defaultSize]['file']) ) {
							@unlink(File::localPath($meta['sizes'][$defaultSize]['uri']));
						}
					} else {
						$backupSizes["$defaultSize-{$suffix}"] = $meta['sizes'][$defaultSize];
					}
				}

				$meta['sizes'][$defaultSize] = $data;
			} else {
				unset($meta['sizes'][$defaultSize]);
			}
		}

		$meta['_backup_sizes'] = $backupSizes;
		$imageModel->meta = $meta;
		if ($imageModel->update(array('meta', 'uri', 'update_time'))) {
			return array(
				'msg' => '图片还原成功'
			);
		} else {
			return array(
				'error' => '图片还原失败'
			);
		}
	}

	/**
	 * @param File $imageModel
	 * @param YImageInterface $image
	 * @param $target
	 * @return bool
	 */
	protected function saveImage(File $imageModel, $image, $target)
	{
		if (isset($imageModel->meta['_backup_sizes'])) {
			$backupSizes = $imageModel->meta['_backup_sizes'];
		} else {
			$backupSizes = array();
		}

		if (!$dimensions = $imageModel->getDimensions()) {
			return false;
		}

		$meta = $imageModel->meta;

		$baseUri = str_replace(basename($imageModel->uri), '', $imageModel->uri);
		if ('/' !== substr($baseUri, -1)) {
			$baseUri .= '/';
		}
		$uriParts = pathinfo($imageModel->uri);
		$filename = $uriParts['filename'];
		$suffix = time() . rand(100, 999);

		if (Yii::app()->option->get('image_edit_overwrite', false) && $backupSizes[File::IMAGE_ORIGIN . '-orig']['uri'] != $imageModel->uri) {
			if ($target === 'thumbnail') {
				$newUri= "{$baseUri}{$filename}-temp.{$uriParts['extension']}";
			} else {
				$newUri = $imageModel->uri;
			}
		} else {
			while (true) {
				$filename  =preg_replace('/-e([0-9]+)$/', '', $filename);
				$filename .= "-e{$suffix}";
				$newFilename = "{$filename}.{$uriParts['extension']}";
				$newUri = "{$baseUri}{$newFilename}";
				if (file_exists(File::localPath($newUri))) {
					$suffix++;
				} else {
					break;
				}
			}
		}

		if (isset($newUri)) {
			$image->save(File::localPath($newUri));
		} else {
			return false;
		}

		if ('nothumb' == $target || 'all' == $target || 'full' == $target || 'scale' == $target) {
			$tag = false;
			if (isset($backupSizes[File::IMAGE_ORIGIN . '-orig'])) {
				if ((!Yii::app()->option->get('image_edit_overwrite', false)) && $backupSizes[File::IMAGE_ORIGIN . '-orig']['uri'] != $imageModel->uri) {
					$tag = File::IMAGE_ORIGIN . "-{$suffix}";
				}
			} else {
				$tag = File::IMAGE_ORIGIN . '-orig';
			}
			if ($tag) {
				$backupSizes[$tag] = array('width' => $dimensions['width'], 'height' => $dimensions['height'], 'uri' => $dimensions['uri']);
			}

			$imageModel->uri = $newUri;

			$size = $image->getSize();
			$meta['sizes'][File::IMAGE_ORIGIN] = array(
				'width' => $size[0],
				'height' => $size[1],
				'uri' => $newUri,
			);

			if ('nothumb' == $target || 'all' == $target) {
				$sizes = File::getIntermediateImageSizes();
				if ('nothumb' == $target) {
					$sizes = array_diff($sizes, array(File::IMAGE_THUMBNAIL));
				}
			}
		} elseif ('thumbnail' == $target) {
			$sizes = array(File::IMAGE_THUMBNAIL);
			$delete = true;
		}

		$imageSizes = $imageModel->imageSizes();
		if (isset($sizes)) {
			$_sizes = array();
			foreach ($sizes as $size) {
				$tag = false;
				if (isset($meta['sizes'][$size])) {
					if (isset($backupSizes["{$size}-orig"])) {
						if (!Yii::app()->option->get('image_edit_overwrite', false) && $backupSizes["{$size}-orig"]['uri'] != $imageModel->uri) {
							$tag = "{$size}-{$suffix}";
						}
					} else {
						$tag = "{$size}-orig";
					}
					if ($tag) {
						$backupSizes[$tag] = $meta['sizes'][$size];
					}
				}
				if (isset($imageSizes[$size])) {
					$_sizes[$size] = array($imageSizes[$size][0], $imageSizes[$size][1], isset($imageSizes[$size][2]) ? $imageSizes[$size][2] : false);
				}
			}
			$meta['sizes'] = array_merge($meta['sizes'], $this->imageMultiResize($image, $_sizes, $newUri));
		}

		$meta['_backup_sizes'] = $backupSizes;
		$imageModel->meta = $meta;

		if (!$imageModel->update(array('meta', 'uri', 'update_time'))) {
			$result = array('error' => '图片保存失败');
		} else {
			if (isset($meta['sizes'][File::IMAGE_THUMBNAIL])) {
				$result['thumbnail'] = File::createUrl($meta['sizes'][File::IMAGE_THUMBNAIL]['uri']);
			}

			if (isset($meta['sizes'][File::IMAGE_ORIGIN])) {
				$result['fw'] = $meta['sizes'][File::IMAGE_ORIGIN]['width'];
				$result['fh'] = $meta['sizes'][File::IMAGE_ORIGIN]['height'];
			}
			$result['msg']='图片保存成功';
		}

		if (!empty($delete)) {
			@unlink(File::localPath($newUri));
		}

		return $result;
	}

	/**
	 * @param YImageInterface $image
	 * @param array $sizes
	 * @param string $uri
	 * @return array
	 */
	public function imageMultiResize($image, $sizes, $uri)
	{
		$metaSizes = array();
		$filePath = File::localPath($uri);
		$parts = pathinfo($filePath);
		$filename = $parts['filename'];
		$ext = $parts['extension'];

		list($sWidth, $sHeight) = $image->getSize();

		$baseUri = str_replace(basename($uri), '', $uri);
		if ('/' !== substr($baseUri, -1)) {
			$baseUri .= '/';
		}

		foreach ($sizes as $name => $size) {
			if (!isset($size[2])) {
				$size[2] = false;
			}

			list($width, $height, $crop) = $size;

			if ($sWidth < $width && $sHeight < $height) {
				continue;
			}

			if (empty($crop)) {
				$thumbnail = $image->thumbnail($width, $height);
			} else {
				$thumbnail = $image->thumbnail($width, $height, YImageInterface::THUMBNAIL_OUTBOUND);
			}

			$imageSize = $thumbnail->getSize();

			if ($name === File::IMAGE_ORIGIN) {
				$saveFilePath = $filePath;
				$dUri = $uri;
			} else {
				$dUri = $baseUri . "{$filename}_{$imageSize[0]}x{$imageSize[1]}.{$ext}";
				$saveFilePath = File::localPath($dUri);
			}

			$thumbnail->save($saveFilePath);
			$metaSizes[$name] = array(
				'uri' => $dUri,
				'width' => $imageSize[0],
				'height' => $imageSize[1],
			);
		}

		return $metaSizes;
	}

	/**
	 * @param YImageInterface $image
	 * @param array $changes
	 * @throws CException
	 * @return \YImageInterface
	 */
	public function imageEditApplyChanges($image, $changes)
	{
		if (!$image instanceof YImageInterface) {
			throw new CException('错误的图片资源');
		}

		if (!is_array($changes)) {
			return $image;
		}

		foreach ($changes as $key => $obj) {
			if (isset($obj->r)) {
				$obj->type = 'rotate';
				$obj->angle = $obj->r;
				unset($obj->r);
			} elseif (isset($obj->f)) {
				$obj->type = 'flip';
				$obj->axis = $obj->f;
				unset($obj->f);
			} elseif (isset($obj->c)) {
				$obj->type = 'crop';
				$obj->sel = $obj->c;
				unset($obj->c);
			}
			$changes[$key] = $obj;
		}

		// combine operations
		if (count($changes) > 1) {
			$filtered = array($changes[0]);
			for ($i = 0, $j = 1; $j < count($changes); $j++) {
				$combined = false;
				if ($filtered[$i]->type == $changes[$j]->type) {
					switch ($filtered[$i]->type) {
						case 'rotate':
							$filtered[$i]->angle += $changes[$j]->angle;
							$combined = true;
							break;
						case 'flip':
							$filtered[$i]->axis ^= $changes[$j]->axis;
							$combined = true;
							break;
					}
				}
				if (!$combined)
					$filtered[++$i] = $changes[$j];
			}
			$changes = $filtered;
			unset($filtered);
		}

		foreach ($changes as $operation) {
			switch ($operation->type) {
				case 'rotate':
					if ($operation->angle != 0) {
						$image->rotate(-$operation->angle);
					}
					break;
				case 'flip':
					if ($operation->axis != 0) {
						$image->flip($operation->axis);
					}
					break;
				case 'crop':
					$sel = $operation->sel;
					list($w, $h) = $image->getSize();
					$scale = 1 / $this->imageGetPreviewRatio($w, $h); // discard preview scaling
					$image->crop($sel->w * $scale, $sel->h * $scale, $sel->x * $scale, $sel->y * $scale);
					break;
			}
		}
	}

	public function imageGetPreviewRatio($width, $height)
	{
		$max = max($width, $height);
		return $max > 400 ? (400 / $max) : 1;
	}
}
